package scope

import (
	"gitee.com/mkwchecking/sr-core/yal/yarr"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
)

type IClause interface {
	IScope

	Clause() clause.Interface
}

func WithConflict(columns []string, updateAll bool, updateCols []string, doNothing bool) IClause {
	return conflict{
		Columns:       columns,
		UpdateAll:     updateAll,
		UpdateColumns: updateCols,
		DoNothing:     doNothing,
	}
}

func WithConflictDoNothing(columns ...string) IClause {
	return conflict{
		Columns:   columns,
		DoNothing: true,
	}
}

func WithConflictPKUpdateAll() IClause {
	return conflict{
		PK:        true,
		UpdateAll: true,
	}
}

func WithConflictUpdateAll(columns ...string) IClause {
	return conflict{
		Columns:   columns,
		UpdateAll: true,
	}
}

type conflict struct {
	// 使用PK
	PK bool

	// 冲突字段
	Columns []string

	// 是否更新所有字段
	UpdateAll bool

	// 更新字段
	UpdateColumns []string

	// DoNothing
	DoNothing bool
}

func (c conflict) MakeScope() Scope {
	return func(db *gorm.DB) *gorm.DB {
		if c.PK {
			newC := conflict{
				Columns:       db.Statement.Schema.PrimaryFieldDBNames,
				UpdateAll:     c.UpdateAll,
				UpdateColumns: c.UpdateColumns,
			}
			return db.Clauses(newC.Clause())
		} else {
			return db.Clauses(c.Clause())
		}
	}
}

func (o conflict) Clause() clause.Interface {

	conf := clause.OnConflict{}
	conf.Columns = yarr.Map(o.Columns, func(s string) clause.Column {
		return clause.Column{Name: s}
	})
	if o.DoNothing {
		conf.DoNothing = true
	} else if o.UpdateAll {
		conf.UpdateAll = true
	} else if len(o.UpdateColumns) > 0 {

		assignments := yarr.Map(
			o.UpdateColumns,
			func(s string) clause.Assignment {
				return clause.Assignment{Column: clause.Column{Name: s}}
			},
		)

		conf.DoUpdates = clause.Set(assignments)
	}

	return conf
}
